typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;

#define RCC_APB2ENR ((volatile u32 *)0x40021018)
#define GPIOA_CRL ((volatile u32 *)0x40010800)
#define GPIOA_CRH ((volatile u32 *)0x40010804)
#define GPIOB_CRL ((volatile u32 *)0x40010C00)
#define GPIOB_CRH ((volatile u32 *)0x40010C04)
#define GPIOA_IDR ((volatile u32 *)0x40010808)
#define GPIOB_IDR ((volatile u32 *)0x40010C08)
#define GPIOA_ODR ((volatile u32 *)0x4001080C)
#define GPIOB_ODR ((volatile u32 *)0x40010C0C)

enum GPIO {
    GPIOA = 0,
    GPIOB,
    GPIOC,
    GPIOD,
};

enum MODE {
    IN = 0,
    OUT,
};

void delay(volatile u32 n) {
    while (n--);
}

// 将GPIOx_PINy设置为高电压
void GPIOx_PINy_SET_HALL(enum GPIO GPIO, int pin) {
    volatile u32 *odr = (GPIO == GPIOA) ? GPIOA_ODR : GPIOB_ODR;
    *odr |= (0x1 << pin);
}

// 将GPIOx_PINy设置为低电压
void GPIOx_PINy_SET_LOW(enum GPIO GPIO, int pin) {
    volatile u32 *odr = (GPIO == GPIOA) ? GPIOA_ODR : GPIOB_ODR;
    *odr &= ~(0x1 << pin);
}

// 读取GPIOx_PINy的电平状态
int GPIOx_PINy_GET_BIT(enum GPIO GPIO, int pin) {
    volatile u32 *idr = (GPIO == GPIOA) ? GPIOA_IDR : GPIOB_IDR;
    return (*idr & (0x1 << pin)) >> pin;
}

// 初始化GPIOx_PINy
void GPIOx_PINy_INIT(enum GPIO GPIO, int pin, enum MODE mode) {
    volatile u32 *crl = (volatile u32 *)0;
    volatile u32 *crh = (volatile u32 *)0;
    int rcc_shift = 0;

    switch (GPIO) {
        case GPIOA:
            crl = GPIOA_CRL;
            crh = GPIOA_CRH;
            rcc_shift = 2;
            break;
        case GPIOB:
            crl = GPIOB_CRL;
            crh = GPIOB_CRH;
            rcc_shift = 3;
            break;
        default:
            return; 
    }

    // 使能GPIO时钟
    *RCC_APB2ENR |= (1 << rcc_shift);

    volatile u32 *cr = (pin < 8) ? crl : crh;
    int shift = (pin < 8) ? (4 * pin) : (4 * (pin - 8));

    *cr &= ~(0xf << shift);
    *cr |= (mode == OUT) ? (0x1 << shift) : (0x4 << shift);
}

int main() {
    int flag = 0;
    GPIOx_PINy_INIT(GPIOA, 0, IN);
    GPIOx_PINy_INIT(GPIOA, 8, OUT);
    GPIOx_PINy_INIT(GPIOB, 0, OUT);
    GPIOx_PINy_INIT(GPIOB, 1, OUT);
    GPIOx_PINy_INIT(GPIOB, 5, OUT);

    while (1)
    {
        if (GPIOx_PINy_GET_BIT(GPIOA, 0) == 1)
        {
            delay(200);
            while (GPIOx_PINy_GET_BIT(GPIOA, 0) == 1)
                ;
            delay(200); // 防止抖动
            flag = (flag + 1) % 7;
        }

        GPIOx_PINy_SET_HALL(GPIOB, 5);
        GPIOx_PINy_SET_HALL(GPIOB, 1);
        GPIOx_PINy_SET_HALL(GPIOB, 0);

        switch (flag)
        {
        case 0:
            GPIOx_PINy_SET_LOW(GPIOB, 5);
            break;
        case 1:
            GPIOx_PINy_SET_LOW(GPIOB, 1);
            break;
        case 2:
            GPIOx_PINy_SET_LOW(GPIOB, 0);
            break;
        case 3:
            GPIOx_PINy_SET_LOW(GPIOB, 5);
            GPIOx_PINy_SET_LOW(GPIOB, 1);
            break;
        case 4:
            GPIOx_PINy_SET_LOW(GPIOB, 5);
            GPIOx_PINy_SET_LOW(GPIOB, 0);
            break;
        case 5:
            GPIOx_PINy_SET_LOW(GPIOB, 1);
            GPIOx_PINy_SET_LOW(GPIOB, 0);
            break;
        case 6:
            GPIOx_PINy_SET_HALL(GPIOA, 8);
            delay(10000);
            GPIOx_PINy_SET_LOW(GPIOA, 8);
            delay(50000);
            break;
        }
    }
}

void SystemInit(void)
{
}
